/*
 * @Descripttion: 负责维护 access_token 的有效性
 * @version: 1.0
 * @Author: 自由如风
 * @Date: 2021-04-13 19:00:56
 * @LastEditors: 自由如风
 * @LastEditTime: 2021-06-27 14:30:08
 */
import _axios from 'axios';
import { create_axios } from '../tool/WXAxios';
import { echo } from '../tool/echo';

/**
 * 负责维护 access_token 的有效性
 */
export default class AccessToken {
    /** 获取成功的访问令牌 */
    public access_token: string | null = null;
    /** 其值是刷新的结果的 Promise ，可以使用 await 等待它 */
    private refresh_result: Promise<boolean> = Promise.resolve(true);
    /** 请求的地址 */
    private readonly TOKEN = 'https://api.weixin.qq.com/cgi-bin/token'

    private axios;// 创建单独实例

    /** 构造函数 */
    constructor(public appid: string, public secret: string, public interval: number = 7000) {
        this.axios = create_axios(); // 处理响应结果
        this.auto()
        this.refresh_result = this.refresh();
    }

    /**
     * 刷新令牌，成功返回 true  失败返回 false
     */
    public async refresh(): Promise<boolean> {
        try {
            // 通过 ajax 请求接口，获取结果，如果 errcode 不为 0 ，则表示 接口请求失败
            const data: {
                /** 获取到的凭证 */
                access_token: string,
                /** 凭证有效时间，单位：秒 */
                expires_in: number
            } = await this.axios.get(this.TOKEN, {
                params: {
                    appid: this.appid,
                    secret: this.secret,
                    grant_type: "client_credential"
                }
            })

            // 如果响应拦截器没有抛出异常，则以正常获取到访问令牌
            this.access_token = data.access_token
            echo(`刷新访问令牌,有效期[${data.expires_in}]秒:${this.access_token}`)
            return true;
        } catch (e) {

            echo(`刷新访问令牌失败:${JSON.stringify(e)}`)
            return false;
        }
    }
    /**
     * 自动刷新access_token
     */
    private auto(): AccessToken {
        /** 
         * 定时器第一次执行时不会立刻执行。
         */
        setInterval(() => {
            this.refresh_result = this.refresh(); // 由于 refresh 是异步函数，将它的 permise 保存起来，即可得知异步函数的结果
        }, this.interval * 1000) // interval 的单位是 秒
        return this;
    }

    /** 
     * 等待刷新完毕才返回。
     */
    public async wait() {
        return await this.refresh_result;
    }

    /** 重写 string 方法 */
    public toString() {
        return this.access_token || '';
    }
}
